import { CENTEREVENTS, CSLine } from '@amcax/base';
import { nextmeshEventCenter } from '@app-cad/environments/nextmesh/common/events/EventCenter';
import Base, { MdEn, PlaneEnum, PlaneType } from '../cmd-common/base';
import { nmAppLog } from '@app-nextmesh/common/utils';
import { State } from './type';
import { Object3D, Vector3, Vector3Tuple } from 'three-legacy';
import { ctx2 } from '@app-base/module';
import { createUpdateLine } from '../cmd-common/tools';
import { documentV2 } from '@app-nextmesh/domain';

export default class CmdInteractor extends Base {
  state: State = State.NONE;
  startPoint: Vector3;
  secondPoint: Vector3;
  assisGroup: Object3D;
  planeType: PlaneType;
  previewData: {
    line: CSLine;
  };
  vertexs: Vector3[];
  constructor(planeType: PlaneType = PlaneEnum.XOY) {
    super();
    this.assisGroup = ctx2.cadScene.assisGroup;
    this.setMode(['plane', 'point']);
    this.setPlaneMode(planeType);
    this.registerEvents();
    this.previewData = {
      line: null,
    };
  }
  setPlaneMode = (plane: PlaneEnum) => {
    this.planeType = plane;
    this.getPlane();
  };
  reset(): void {
    this.state = State.NONE;
    this.previewData?.line?.destroy();
    this.previewData.line = null;
  }
  registerEvents = () => {
    nextmeshEventCenter()
      .setState('cmd-mesh-ellipse')
      .on(CENTEREVENTS.POINTERMOVE, this.onMouseMove)
      .on(CENTEREVENTS.POINTERDOWN, this.onMouseUp)
      .on(CENTEREVENTS.KEYUP, this.onKeyUp)
      .addExit(this.destroy);
  };
  unregisterEvents = () => {
    nextmeshEventCenter()
      .off(CENTEREVENTS.POINTERMOVE, this.onMouseMove)
      .off(CENTEREVENTS.POINTERDOWN, this.onMouseUp)
      .off(CENTEREVENTS.KEYUP, this.onKeyUp)
      .setDefault();
  };
  onMouseMove = (e) => {
    if (this.state === State.NONE) {
      this.mouseMove(e, false);
    } else {
      const mouseXY = this.getMouseWorldVector(e.mouse);
      this.preView([this.startPoint, mouseXY]);
    }
  };
  onMouseUp = (e) => {
    if (!e.button.onLeft) {
      return;
    }
    if (this.state === State.NONE) {
      if (this.pickInfo?.assisObj) {
        const mouseup = this.mouseUp(e);
        this.startPoint = new Vector3(...mouseup.point);
        this.getPlane(
          mouseup.point,
          this.entityType === MdEn.FACE && PlaneEnum.FREE,
        );
      } else {
        this.startPoint = this.getMouseWorldVector(e.mouse);
      }
      this.state = State.DRAW;
    } else if (this.state === State.DRAW) {
      this.finish();
      this.state = State.FINSH;
    }
  };
  async finish() {
    await this.onExecute(false);
    this.close();
  }
  onExecute = async (preview: boolean) => {
    const [p1, p2, p3] = this.vertexs;
    const vx = new Vector3().subVectors(p2, p1).divideScalar(2);
    const vy = new Vector3().subVectors(p3, p2).divideScalar(2);
    const source: Vector3Tuple[] = [
      this.startPoint?.toArray(),
      vx.toArray(),
      vy.toArray(),
    ];
    try {
      return await documentV2.basicCurve(
        { source, mode: 'rectangle' },
        preview,
      );
    } catch (error) {
      //
    }
  };
  preView(vertexs: Vector3[]) {
    if (this.state === State.DRAW) {
      const p12d = this.change2D(vertexs[0]);
      const p22d = this.change2D(vertexs[1]);
      this.previewData.line = createUpdateLine(
        this.getVertices(p12d, p22d),
        this.previewData.line,
        this.assisGroup,
      ); //  绘制预览线
      ctx2.viewer.requestRender();
    }
  }
  getVertices(startPoint: Vector3, endPoint: Vector3) {
    const offsetx = endPoint.x - startPoint.x;
    const offsety = endPoint.y - startPoint.y;
    const point1 = new Vector3(
      startPoint.x - offsetx,
      startPoint.y + offsety,
      0,
    );
    const point2 = new Vector3(
      startPoint.x + offsetx,
      startPoint.y + offsety,
      0,
    );
    const point3 = new Vector3(
      startPoint.x + offsetx,
      startPoint.y - offsety,
      0,
    );
    const point4 = new Vector3(
      startPoint.x - offsetx,
      startPoint.y - offsety,
      0,
    );
    this.vertexs = [point1, point2, point3, point4, point1].map((v) =>
      this.change3D(v),
    );
    return this.vertexs;
  }
  getPlane = (point?: Vector3Tuple, planeType?: PlaneEnum) => {
    const type = planeType || this.planeType;
    const origin = point || this.startPoint?.toArray() || [0, 0, 0];
    this.setPlacement(origin, type);
  };
  onEnter = () => {
    nmAppLog('enter');
  };
  destroy = () => {
    this.reset();
    this.unregisterEvents();
    this.removePointArrow();
    this.assisGroup?.clear();
  };
  close = () => {
    this.destroy();
    this.exitFunc?.();
  };
  addExit(exitFunc: () => void) {
    this.exitFunc = exitFunc;
  }
}
